package com.engine.cn.juc;

import lombok.Data;

import java.math.BigDecimal;
import java.util.concurrent.atomic.AtomicStampedReference;

@Data
public class BankAccount {
    private String accountNumber;
    private AtomicStampedReference<BigDecimal> balance;

    public BankAccount(String accountNumber, BigDecimal balance) {
        this.accountNumber = accountNumber;
        this.balance = new AtomicStampedReference<>(balance, 0);
    }

    /**
     * 存款
     *
     * @param amount 存款数量
     */
    public boolean deposit(BigDecimal amount) {
        while (true) {
            int[] stampHolder = new int[1];
            BigDecimal current = balance.get(stampHolder);
            BigDecimal result = current.add(amount);
            if (balance.compareAndSet(current, result, stampHolder[0], stampHolder[0] + 1)) {
                return true;
            }

            //CAS失败自旋重试
        }
    }

    /**
     * 取款
     *
     * @param amount 取款数量
     */
    public boolean withdraw(BigDecimal amount) {
        while (true) {
            int[] stampHolder = new int[1];
            BigDecimal current = balance.get(stampHolder);
            if (current.compareTo(amount) < 0) {
                return false;
            }

            BigDecimal result = current.subtract(amount);
            if (balance.compareAndSet(current, result, stampHolder[0], stampHolder[0] + 1)) {
                return true;
            }

            //CAS失败自旋重试
        }
    }

    public BigDecimal getBalance() {
        return balance.getReference();
    }

    public static void main(String[] args) throws InterruptedException {
        BankAccount ak = new BankAccount("日常打工人", new BigDecimal(100));
        new Thread(() -> {
            boolean result = ak.deposit(new BigDecimal(50));
            System.out.println("存款结果: " + result + ",剩余钱数：" + ak.getBalance());
        }).start();

        new Thread(() -> {
            boolean result = ak.withdraw(new BigDecimal(30));
            System.out.println("取款结果: " + result + ",剩余钱数：" + ak.getBalance());
        }).start();
    }
}
